package ostt1_TokenLib;
import java.io.Serializable;
import java.security.InvalidKeyException;
import java.security.PublicKey;
import java.security.SignatureException;
import iaik.pkcs.pkcs10.CertRequest;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;
import iaik.asn1.ASN;
import iaik.asn1.ASN1;
import iaik.asn1.ASN1Object;
import iaik.asn1.BIT_STRING;
import iaik.asn1.CON_SPEC;
import iaik.asn1.CodingException;
import iaik.asn1.ConstructedType;
import iaik.asn1.DerCoder;
import iaik.asn1.INTEGER;
import iaik.asn1.ObjectID;
import iaik.asn1.SEQUENCE;
import iaik.asn1.SET;
import iaik.asn1.structures.AlgorithmID;
import iaik.asn1.structures.Attribute;
import iaik.asn1.structures.AttributeValue;
import iaik.asn1.structures.Name;
import iaik.pkcs.PKCSException;
import iaik.pkcs.PKCSParsingException;
import iaik.utils.Util;
import iaik.x509.PublicKeyInfo;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Vector;


public class CustomCertificateRequest implements CertRequest, Serializable{
	  static Class g;
	  private byte[] j;
	  private boolean k;
	  private Attribute[] i;
	  private byte[] f;
	  private AlgorithmID c;
	  private PublicKey e;
	  private byte[] pubkeymodulus;
	  private Name b;
	  private int a;
	  private ASN1 h;
	  static Class a(String paramString)
	  {
	    try
	    {
	      return Class.forName(paramString);
	    }
	    catch (ClassNotFoundException localClassNotFoundException)
	    {
	      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
	    }
	  }
	  
	  public void writeTo(OutputStream paramOutputStream)
	    throws IOException
	  {
	    c();
	    this.h.writeTo(paramOutputStream);
	  }
	  
	  private void writeObject(ObjectOutputStream paramObjectOutputStream)
	    throws IOException
	  {
	    paramObjectOutputStream.write(toByteArray());
	  }
	  
	  public boolean verify(String paramString)
	    throws SignatureException
	  {
	    c();
	    try
	    {
	      Signature localSignature = this.c.getSignatureInstance(paramString);
	      byte[] arrayOfByte = this.h.getFirstObject();
	      localSignature.initVerify(this.e);
	      localSignature.update(arrayOfByte);
	      return localSignature.verify(this.f);
	    }
	    catch (CodingException localCodingException)
	    {
	      throw new SignatureException(localCodingException.getMessage());
	    }
	    catch (NoSuchAlgorithmException localNoSuchAlgorithmException)
	    {
	      throw new SignatureException(localNoSuchAlgorithmException.getMessage());
	    }
	    catch (InvalidKeyException localInvalidKeyException)
	    {
	      throw new SignatureException(localInvalidKeyException.getMessage());
	    }
	  }
	  
	  public boolean verify()
	    throws SignatureException
	  {
	    return verify(null);
	  }
	  
	  public String toString(boolean paramBoolean)
	  {
	    StringBuffer localStringBuffer = new StringBuffer();
	    localStringBuffer.append("Version: " + this.a + "\n");
	    if (this.b != null) {
	      localStringBuffer.append("Subject: " + this.b + "\n");
	    }
	    if (this.e != null) {
	      localStringBuffer.append(this.e.toString());
	    }
	    if (this.c != null) {
	      localStringBuffer.append("Signature algorithm: " + this.c + "\n");
	    }
	    localStringBuffer.append("\n");
	    if ((this.i != null) && (this.i.length > 0)) {
	      if (paramBoolean) {
	        for (int m = 0; m < this.i.length; m++)
	        {
	          localStringBuffer.append("Attribute " + (m + 1) + ": ");
	          localStringBuffer.append(this.i[m]);
	          localStringBuffer.append("\n");
	        }
	      } else {
	        localStringBuffer.append("Attributes: yes\n");
	      }
	    }
	    localStringBuffer.append("Fingerprint (MD5)  : " + Util.toString(getFingerprint()) + "\n");
	    localStringBuffer.append("Fingerprint (SHA-1): " + Util.toString(getFingerprintSHA()) + "\n");
	    return localStringBuffer.toString();
	  }
	  
	  public String toString()
	  {
	    return toString(false);
	  }
	  
	  public byte[] toByteArray()
	  {
	    c();
	    return this.h.toByteArray();
	  }
	  
	  public void sign(AlgorithmID paramAlgorithmID, PrivateKey paramPrivateKey, String paramString)
	    throws NoSuchAlgorithmException, InvalidKeyException, SignatureException
	  {
	    if (paramPrivateKey == null) {
	      throw new SignatureException("Cannot sign this request. No algorithm specified!");
	    }
	    if (paramAlgorithmID == null) {
	      throw new InvalidKeyException("Cannot sign this request. No private key specified!");
	    }
	    this.c = paramAlgorithmID;
	    //System.out.println(this.c.toASN1Object());
	    Signature localSignature = this.c.getSignatureInstance(paramString);
	    try
	    {
	      ASN1Object localASN1Object = a();
	      localSignature.initSign(paramPrivateKey);
	      localSignature.update(DerCoder.encode(localASN1Object));
	      this.f = localSignature.sign();
	      BIT_STRING localBIT_STRING = new BIT_STRING(this.f);
	      SEQUENCE localSEQUENCE = null;
	      localSEQUENCE = new SEQUENCE();
	      localSEQUENCE.addComponent(localASN1Object);
	      localSEQUENCE.addComponent(this.c.toASN1Object());
	      localSEQUENCE.addComponent(localBIT_STRING);
	      this.h = new ASN1(localSEQUENCE);
	      d();
	      e();
	      return;
	    }
	    catch (CodingException localCodingException)
	    {
	      throw new SignatureException("Cann't sign CertRequest!");
	    }
	  }
	  /*
	  public void sign(AlgorithmID paramAlgorithmID, long handleKey)
			    throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, PKCS11Exception
	  {
	    if (paramAlgorithmID == null) {
	      throw new InvalidKeyException("Cannot create this request. No paramAlgorithmID specified!");
	    }
	    this.c = paramAlgorithmID;
	    Signature localSignature = this.c.getSignatureInstance(null);
	    try
	    {
	      ASN1Object localASN1Object = a();
	      
//	      localSignature.initSign(paramPrivateKey);
//	      localSignature.update(DerCoder.encode(localASN1Object));
//	      this.f = localSignature.sign();
	      this.f = P11Other.signData(DerCoder.encode(localASN1Object), handleKey, PKCS11Constants.CKM_SHA1_RSA_PKCS);
	      BIT_STRING localBIT_STRING = new BIT_STRING(this.f);
	      SEQUENCE localSEQUENCE = null;
	      localSEQUENCE = new SEQUENCE();
	      localSEQUENCE.addComponent(localASN1Object);
	      localSEQUENCE.addComponent(this.c.toASN1Object());
	      localSEQUENCE.addComponent(localBIT_STRING);
	      this.h = new ASN1(localSEQUENCE);
	      d();
	      e();
	      return;
	    }
	    catch (CodingException localCodingException)
	    {
	      throw new SignatureException("Cann't sign CertRequest!");
	    }
	  }
	  */
	  public void sign(AlgorithmID paramAlgorithmID, PrivateKey paramPrivateKey)
	    throws NoSuchAlgorithmException, InvalidKeyException, SignatureException
	  {
	    sign(paramAlgorithmID, paramPrivateKey, null);
	  }
	  
	  private void e()
	  {
	    this.k = false;
	  }
	  
	  public void setSignature(AlgorithmID paramAlgorithmID, byte[] paramArrayOfByte)
	    throws SignatureException
	  {
	    if (paramAlgorithmID == null) {
	      throw new SignatureException("Cannot sign this request. No signature algorithm specified!");
	    }
	    if (paramArrayOfByte == null) {
	      throw new SignatureException("Cannot sign this request. No signature value specified!");
	    }
	    this.c = paramAlgorithmID;
	    this.f = paramArrayOfByte;
	    try
	    {
	      ASN1Object localASN1Object = a();
	      BIT_STRING localBIT_STRING = new BIT_STRING(this.f);
	      SEQUENCE localSEQUENCE = null;
	      localSEQUENCE = new SEQUENCE();
	      localSEQUENCE.addComponent(localASN1Object);
	      localSEQUENCE.addComponent(this.c.toASN1Object());
	      localSEQUENCE.addComponent(localBIT_STRING);
	      this.h = new ASN1(localSEQUENCE);
	      d();
	      e();
	      return;
	    }
	    catch (CodingException localCodingException)
	    {
	      throw new SignatureException("Cann't sign CertRequest!");
	    }
	  }
	  
	  private void d()
	  {
	    this.k = true;
	    this.j = null;
	  }
	  
	  public void setAttributes(Attribute[] paramArrayOfAttribute)
	  {
	    this.i = paramArrayOfAttribute;
	    d();
	  }
	  
	  private void readObject(ObjectInputStream paramObjectInputStream)
	    throws ClassNotFoundException, IOException
	  {
	    try
	    {
	      this.h = new ASN1(paramObjectInputStream);
	      b();
	      return;
	    }
	    catch (CodingException localCodingException)
	    {
	      throw new IOException("Unable to restore CustomCertificateRequest: " + localCodingException.toString());
	    }
	    catch (PKCSParsingException localPKCSParsingException)
	    {
	      throw new IOException("Unable to restore CustomCertificateRequest: " + localPKCSParsingException.toString());
	    }
	  }
	  
	  public int getVersion()
	  {
	    return this.a;
	  }
	  
	  public Name getSubject()
	  {
	    return this.b;
	  }
	  
	  public AlgorithmID getSignatureAlgorithmID()
	  {
	    return this.c;
	  }
	  
	  public PublicKey getPublicKey()
	  {
	    return this.e;
	  }
	  
	  public byte[] getFingerprintSHA()
	  {
	    if (this.j == null) {
	      try
	      {
	        this.j = getFingerprint("SHA");
	      }
	      catch (NoSuchAlgorithmException localNoSuchAlgorithmException)
	      {
	        throw new RuntimeException("Algorithm SHA not available: " + localNoSuchAlgorithmException.toString());
	      }
	    }
	    return this.j;
	  }
	  
	  public byte[] getFingerprint(String paramString)
	    throws NoSuchAlgorithmException
	  {
	    c();
	    MessageDigest localMessageDigest = MessageDigest.getInstance(paramString);
	    localMessageDigest.update(this.h.toByteArray());
	    return localMessageDigest.digest();
	  }
	  
	  public byte[] getFingerprint()
	  {
	    c();
	    return this.h.fingerprint();
	  }
	  
	  public byte[] getCustomCertificateRequestInfo()
	    throws PKCSException
	  {
	    try
	    {
	      if ((this.h != null) && (this.h.toByteArray() != null)) {
	        return this.h.getFirstObject();
	      }
	      return DerCoder.encode(a());
	    }
	    catch (CodingException localCodingException)
	    {
	      throw new PKCSException(localCodingException.toString());
	    }
	  }
/*	  
	  public Attribute[] getAttributes(ObjectID paramObjectID)
	  {
	    if (this.i == null) {
	      return null;
	    }
	    Vector localVector = new Vector();
	    for (int m = 0; m < this.i.length; m++)
	    {
	      localObject = this.i[m];
	      if (((Attribute)localObject).getType().equals(paramObjectID)) {
	        localVector.addElement(this.i[m]);
	      }
	    }
	    if (localVector.isEmpty()) {
	      return null;
	    }
	    Object localObject = new Attribute[localVector.size()];
	    localVector.copyInto((Object[])localObject);
	    return localObject;
	  }
*/	  
	  public Attribute[] getAttributes()
	  {
	    return this.i;
	  }
	  
	  public AttributeValue getAttributeValue(ObjectID paramObjectID)
	    throws PKCSException
	  {
	    Attribute localAttribute = getAttribute(paramObjectID);
	    if (localAttribute != null) {
	      try
	      {
	        return localAttribute.getAttributeValue();
	      }
	      catch (CodingException localCodingException)
	      {
	        throw new PKCSException("Cannot decode attribute " + paramObjectID.getName() + ": " + localCodingException.getMessage());
	      }
	    }
	    return null;
	  }
	  
	  public Attribute getAttribute(ObjectID paramObjectID)
	  {
	    if (this.i == null) {
	      return null;
	    }
	    for (int m = 0; m < this.i.length; m++) {
	      if (this.i[m].getType().equals(paramObjectID)) {
	        return this.i[m];
	      }
	    }
	    return null;
	  }
	  
	  private void b()
	    throws PKCSParsingException
	  {
	    try
	    {
	      ASN1Object localASN1Object1 = this.h.getComponentAt(0);
	      this.c = new AlgorithmID(this.h.getComponentAt(1));
	      ASN1Object localASN1Object2 = this.h.getComponentAt(2);
	      this.f = ((byte[])((BIT_STRING)localASN1Object2).getValue());
	      this.a = ((BigInteger)localASN1Object1.getComponentAt(0).getValue()).intValue();
	      this.b = new Name(localASN1Object1.getComponentAt(1));
	      try
	      {
	        this.e = PublicKeyInfo.getPublicKey(localASN1Object1.getComponentAt(2));
	      }
	      catch (InvalidKeyException localInvalidKeyException)
	      {
	        throw new PKCSParsingException("Unable to create PublicKey: " + localInvalidKeyException.toString());
	      }
	      if (localASN1Object1.countComponents() > 3)
	      {
	        ASN1Object localASN1Object3 = localASN1Object1.getComponentAt(3);
	        ((CON_SPEC)localASN1Object3).forceImplicitlyTagged(ASN.SEQUENCE);
	        if (localASN1Object3.getAsnType().getTag() == 0) {
	          this.i = ((Attribute[])ASN.parseSequenceOf((ASN1Object)localASN1Object3.getValue(), CustomCertificateRequest.g = a("iaik.asn1.structures.Attribute")));
	        } else {
	          throw new PKCSParsingException("Unknown context specific tag: " + localASN1Object3.getAsnType().getTag());
	        }
	      }
	      this.h.clearASN1Object();
	      e();
	      return;
	    }
	    catch (RuntimeException localRuntimeException)
	    {
	      throw new PKCSParsingException("Certificate request format error: " + localRuntimeException.toString());
	    }
	    catch (CodingException localCodingException)
	    {
	      throw new PKCSParsingException(localCodingException.toString());
	    }
	  }
	  
	  private ASN1Object a()
	    throws CodingException
	  {
	    SEQUENCE localSEQUENCE = new SEQUENCE();
	    localSEQUENCE.addComponent(new INTEGER(this.a));
	    localSEQUENCE.addComponent(this.b.toASN1Object());
	    localSEQUENCE.addComponent(DerCoder.decode(this.e.getEncoded()));
	    if (this.i != null) {
	      localSEQUENCE.addComponent(new CON_SPEC(0, ASN.createSetOf(this.i), true));
	    } else {
	      localSEQUENCE.addComponent(new CON_SPEC(0, new SET(), true));
	    }
	    return localSEQUENCE;
	  }
	  
	  private void c()
	  {
	    if (this.k) {
	      throw new RuntimeException("Cannot perform operation, certificate has to be signed first");
	    }
	  }
	  
	  public void addAttribute(Attribute paramAttribute)
	  {
	    if (this.i == null)
	    {
	      this.i = new Attribute[] { paramAttribute };
	      return;
	    }
	    Attribute[] arrayOfAttribute = new Attribute[this.i.length + 1];
	    System.arraycopy(this.i, 0, arrayOfAttribute, 0, this.i.length);
	    arrayOfAttribute[this.i.length] = paramAttribute;
	    this.i = arrayOfAttribute;
	    d();
	  }
	  
	  public CustomCertificateRequest(byte[] paramArrayOfByte)
	    throws PKCSParsingException
	  {
	    try
	    {
	      this.h = new ASN1(paramArrayOfByte);
	      b();
	      return;
	    }
	    catch (CodingException localCodingException)
	    {
	      throw new PKCSParsingException(localCodingException.toString());
	    }
	  }
	  
	  public CustomCertificateRequest(PublicKey paramPublicKey, Name paramName)
	    throws InvalidKeyException
	  {
	    this.e = paramPublicKey;
	    this.b = paramName;
	    d();
	    this.a = 0;
	  }
	  
	  public CustomCertificateRequest(byte[] modulusOfPubKey, Name paramName)
	  {
		  this.b = paramName;
		  this.pubkeymodulus = modulusOfPubKey;
		  d();
		  this.a = 0;
	  }
	  
	  public CustomCertificateRequest(InputStream paramInputStream)
	    throws PKCSParsingException, IOException
	  {
	    try
	    {
	      this.h = new ASN1(paramInputStream);
	      b();
	      return;
	    }
	    catch (CodingException localCodingException)
	    {
	      throw new PKCSParsingException(localCodingException.toString());
	    }
	  }
	  
	  static
	  {
	    Util.toString(null, -1, 1);
	  }

}
